package com.harmontronics.hanma.paas.paas.domain.app.service;

import com.harmontronics.hanma.paas.paas.consts.DbConstants;
import com.harmontronics.hanma.paas.paas.domain.app.entity.DataSourceActiveInfo;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.I18nKeyEnum;
import com.harmontronics.hanma.paas.paas.domain.app.repository.persistence.HmDatasourceRepository;
import com.harmontronics.hanma.paas.paas.domain.app.repository.po.HmDatasourcePO;
import com.harmontronics.hanma.paas.paas.domain.app.service.dialect.DialectDecision;
import com.harmontronics.hanma.paas.paas.exception.ErrorKeyException;
import com.harmontronics.hanma.paas.paas.utils.RequestUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ldb
 */
@Service("datasourceHolder")
public class DataSourceHolder {

    private final Map<String, DataSourceActiveInfo> DATA_SOURCE_CACHE_MAP = new ConcurrentHashMap<>();

    @Autowired
    private HmDatasourceRepository hmDatasourceRepository;

    @Autowired
    private DialectDecision dialectDecision;

    public DataSource getDataSource(String dsKey) {
        String appUnique = RequestUtils.getAppUnique();

        String keyPrefix = appUnique == null ? DbConstants.DS_MASTER_NAME : appUnique.split("_")[1];
        String key = keyPrefix + ":" + dsKey;

        DataSourceActiveInfo dataSourceActiveInfo = DATA_SOURCE_CACHE_MAP.get(key);
        if (dataSourceActiveInfo != null) {
            dataSourceActiveInfo.setLastGetMill(System.currentTimeMillis());
            return dataSourceActiveInfo.getDataSource();
        }
        synchronized (key) {
            dataSourceActiveInfo = DATA_SOURCE_CACHE_MAP.get(key);
            if (dataSourceActiveInfo != null) {
                return dataSourceActiveInfo.getDataSource();
            }
            HmDatasourcePO datasourcePO = hmDatasourceRepository.findByKey(dsKey);
            if (datasourcePO == null) {
                throw new ErrorKeyException(I18nKeyEnum.DATA_SOURCE_NOT_FOUND);
            }
            HikariDataSource dataSource = dialectDecision.getService(datasourcePO.getId()).createDatasource(datasourcePO.getId());
            DATA_SOURCE_CACHE_MAP.put(key, new DataSourceActiveInfo(dataSource, System.currentTimeMillis()));
            return dataSource;

        }
    }


    public void clean() {
        Iterator<Map.Entry<String, DataSourceActiveInfo>> iterator = DATA_SOURCE_CACHE_MAP.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, DataSourceActiveInfo> entry = iterator.next();
            DataSourceActiveInfo activeInfo = entry.getValue();
            if (System.currentTimeMillis() - activeInfo.getLastGetMill() > 30 * 60 * 1000) {
                activeInfo.getDataSource().close();
                iterator.remove();
            }
        }

    }
}
